/*
 * 文 件 名:  ImageUtils.java
 * 版    权:  Huawei Technologies Co., Ltd. Copyright YYYY-YYYY,  All rights reserved
 * 描    述:  <描述>
 * 修 改 人:  ChangJun
 * 修改时间:  2015年5月22日
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.jsits.v2x.common.util;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import org.apache.commons.lang3.StringUtils;

import sun.awt.image.ImageFormatException;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * 图片工具类
 * 
 * @author  ChangJun
 * @version  [版本号, 2015年5月22日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class ImageUtils
{
    /**
     * 合成图片(如果图片大小不一致以第一张图片的宽度和长度为基准进行拼接)
     * 
     * @param picPath 图片路径
     * @param destPath 合成目标位置
     * @param col 指定一行几列
     * @return 返回生成图片
     * @throws IOException 
     * @see [类、类#方法、类#成员]
     */
    public static File picMerge(List<String> picPath, String destPath, int col)
        throws IOException
    {
        int width = 0;
        int height = 0;
        // 计算出需要多少行
        int rowNum = picPath.size() % col == 0 ? picPath.size() / col : picPath.size() / col + 1;
        
        List<int[]> imageArrayList = new ArrayList<int[]>(picPath.size());
        // 将所有的图片转换成RGB数组
        for (int i = 0; i < picPath.size(); i++)
        {
            File file = new File(picPath.get(i));
            BufferedImage image = ImageIO.read(file);
            
            width = image.getWidth() > width && width != 0 ? width : image.getWidth();// 获取最小的图片宽度
            height = image.getHeight() > height && height != 0 ? height : image.getHeight();// 获取最小的图片高度
            
            int[] imageArray = new int[width * height];// 从图片中读取RGB
            imageArray = image.getRGB(0, 0, width, height, imageArray, 0, width);
            
            imageArrayList.add(imageArray);
        }
        
        // 生成新图片(设置图片大小)
        BufferedImage imageResult = new BufferedImage(width * col, height * rowNum, BufferedImage.TYPE_INT_RGB);
        
        int listCount = 0;
        
        for (int i = 0; i < rowNum; i++)
        {
            for (int j = 0; j < col && listCount < imageArrayList.size(); j++)
            {
                imageResult.setRGB(width * j, height * i, width, height, imageArrayList.get(listCount), 0, width);
                listCount++;
            }
        }
        
        File outFile = new File(destPath);
        // 获取图片截取类型
        String endName = outFile.getName().substring(outFile.getName().lastIndexOf(".") + 1);
        ImageIO.write(imageResult, endName, outFile);// 写图片
        
        return outFile;
    }
    
    
    /**
     * 合成图片(如果图片大小不一致以第一张图片的宽度和长度为基准进行拼接)
     * 
     * @param picPath 图片路径
     * @param destPath 合成目标位置
     * @param col 指定一行几列
     * @return 返回生成图片
     * @throws IOException 
     * @see [类、类#方法、类#成员]
     */
    public static byte[] picMergeToByte(List<String> picPath, int col)
        throws IOException
    {
        int width = 0;
        int height = 0;
        // 计算出需要多少行
        int rowNum = picPath.size() % col == 0 ? picPath.size() / col : picPath.size() / col + 1;
        
        List<int[]> imageArrayList = new ArrayList<int[]>(picPath.size());
        // 将所有的图片转换成RGB数组
        for (int i = 0; i < picPath.size(); i++)
        {
            File file = new File(picPath.get(i));
            BufferedImage image = ImageIO.read(file);
            
            width = image.getWidth() > width && width != 0 ? width : image.getWidth();// 获取最小的图片宽度
            height = image.getHeight() > height && height != 0 ? height : image.getHeight();// 获取最小的图片高度
            
            int[] imageArray = new int[width * height];// 从图片中读取RGB
            imageArray = image.getRGB(0, 0, width, height, imageArray, 0, width);
            
            imageArrayList.add(imageArray);
        }
        
        // 生成新图片(设置图片大小)
        BufferedImage imageResult = new BufferedImage(width * col, height * rowNum, BufferedImage.TYPE_INT_RGB);
        
        int listCount = 0;
        
        for (int i = 0; i < rowNum; i++)
        {
            for (int j = 0; j < col && listCount < imageArrayList.size(); j++)
            {
                imageResult.setRGB(width * j, height * i, width, height, imageArrayList.get(listCount), 0, width);
                listCount++;
            }
        }
        
        return bufferedImageToBytes(imageResult);
    }


    /** <一句话功能简述>
     * <功能详细描述>
     * @param imageResult
     * @return
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static byte[] bufferedImageToBytes(BufferedImage imageResult)
        throws IOException
    {
        // 获取图片截取类型
        ByteArrayOutputStream os = null;
        try
        {
            os = new ByteArrayOutputStream();
            // 获取图片截取类型
            ImageIO.write(imageResult, "jpg", os);
            return os.toByteArray();  
        }
        finally
        {
            CloseUtils.close(os);
        }
    }
    
    
    /**
     * 合成图片(如果图片大小不一致以第一张图片的宽度和长度为基准进行拼接)(jpg)
     * 
     * @param pic 图片字节流
     * @param col 指定一行几列
     * @return 返回生成图片字节流
     * @throws IOException 
     * @see [类、类#方法、类#成员]
     */
    public static byte[] picMerge(List<byte[]> pic, int col)
        throws IOException
    {
        int width = 0;
        int height = 0;
        // 计算出需要多少行
        int rowNum = pic.size() % col == 0 ? pic.size() / col : pic.size() / col + 1;
        
        List<int[]> imageArrayList = new ArrayList<int[]>(pic.size());
        // 将所有的图片转换成RGB数组
        
        for (byte[] img : pic)
        {
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(img));
            
            width = image.getWidth() > width && width != 0 ? width : image.getWidth();// 获取最小的图片宽度
            height = image.getHeight() > height && height != 0 ? height : image.getHeight();// 获取最小的图片高度
            
            int[] imageArray = new int[width * height];// 从图片中读取RGB
            imageArray = image.getRGB(0, 0, width, height, imageArray, 0, width);
            
            imageArrayList.add(imageArray);
        }
        
        // 生成新图片(设置图片大小)
        BufferedImage imageResult = new BufferedImage(width * col, height * rowNum, BufferedImage.TYPE_INT_RGB);
        
        int listCount = 0;
        
        for (int i = 0; i < rowNum; i++)
        {
            for (int j = 0; j < col && listCount < imageArrayList.size(); j++)
            {
                imageResult.setRGB(width * j, height * i, width, height, imageArrayList.get(listCount), 0, width);
                listCount++;
            }
        }
        
        return bufferedImageToBytes(imageResult);
        
    }
    
    
    /**
     * 横向或者纵向合成图片(如果图片大小不一致以所有图片中最小的宽度和长度为基准进行拼接,多余的部分自动裁剪)
     * 
     * @param picPath 图片路径
     * @param destPath 合成目标地址
     * @param picType 图片格式(jpg,bmp等)
     * @param isX   是否是横向 (不是横向就是纵向)
     * @return 返回最后生成图片地址
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static File picMergeXY(List<String> picPath, String destPath, boolean isX)
        throws IOException
    {
        int width = 0;
        int height = 0;
        int wSize = 1;
        int hSize = 1;
        
        // 判断是横向还是纵向的设置的起始方式不一样
        if(isX)
        {
            wSize = picPath.size();
        }
        else 
        {
            hSize = picPath.size();
        }
        
        List<int[]> imageArrayList = new ArrayList<int[]>(picPath.size());
        // 将所有的图片转换成RGB数组
        for (int i = 0; i < picPath.size(); i++)
        {
            File file = new File(picPath.get(i));
            BufferedImage image = ImageIO.read(file);
            
            width = image.getWidth() > width && width !=0 ? width : image.getWidth();// 获取最小的图片宽度
            height = image.getHeight() > height && height !=0 ? height : image.getHeight();// 获取最小的图片高度
            
            int[] imageArray = new int[width * height];// 从图片中读取RGB
            imageArray = image.getRGB(0, 0, width, height, imageArray, 0, width);
            
            imageArrayList.add(imageArray);
        }
        
        // 生成新图片(设置图片大小)
        BufferedImage imageResult = new BufferedImage(width * wSize, height * hSize, BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < imageArrayList.size(); i++)
        {
            if (isX)
            {
                imageResult.setRGB(width * i, 0, width, height, imageArrayList.get(i), 0, width);// 从左往右设置图片的RGB
            }
            else 
            {
                imageResult.setRGB(0, height * i, width, height, imageArrayList.get(i), 0, width);// 从上往下设置图片大小
            }
        }
        File outFile = new File(destPath);
        // 获取图片截取类型
        String endName = outFile.getName().substring(outFile.getName().lastIndexOf(".") + 1);
        ImageIO.write(imageResult, endName, outFile);// 写图片
        
        return outFile;
    }
    
    
    /**
     * 图片剪切
     * @param sorcePath 原图片地址
     * @param destPath 剪切完成后存放地址
     * @param x 起始坐标x
     * @param y 起始坐标y
     * @param width 宽度
     * @param height   高度
     * @return 生成的文件
     * @throws IOException 
     * @see [类、类#方法、类#成员]
     */
    public static File cutting(String sorcePath, String destPath, int x, int y, int width, int height) throws IOException
    {
        ImageOutputStream out = null;
        InputStream is = null;
        ImageInputStream iis = null;
        File file = new File(sorcePath);
        try
        {
            String endName = file.getName();
            
            // 获取图片截取类型
            endName = endName.substring(endName.lastIndexOf(".") + 1);
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(endName);
            ImageReader reader = (ImageReader)readers.next();
            is = new FileInputStream(file);
            iis = ImageIO.createImageInputStream(is);
            reader.setInput(iis, true);
            
            ImageReadParam param = reader.getDefaultReadParam();
            Rectangle rect = new Rectangle(x, y, width, height);
            param.setSourceRegion(rect);
            BufferedImage bi = reader.read(0, param);
            File newFile = new File(destPath);
            
            out = ImageIO.createImageOutputStream(new FileOutputStream(newFile));
            ImageIO.write(bi, endName, out);
            file = newFile;
        }
        finally
        {
            CloseUtils.close(iis);
            CloseUtils.close(is);
            CloseUtils.close(out);
        }
        return file;
    }
    
    /**
     * 图片剪切
     * @param sorcePath 原图片地址
     * @param destPath 剪切完成后存放地址
     * @param x 起始坐标x
     * @param y 起始坐标y
     * @param width 宽度
     * @param height   高度
     * @return 生成的文件
     * @throws IOException 
     * @see [类、类#方法、类#成员]
     */
    public static byte[] cuttToByte(URL sorcePath, int x, int y, int width, int height) throws IOException
    {
        ImageOutputStream out = null;
        InputStream is = null;
        ImageInputStream iis = null;
        BufferedImage img = ImageIO.read(sorcePath); // 构造Image对象
        try
        {
            
            // 获取图片截取类型
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader)readers.next();
            is = new ByteArrayInputStream(bufferedImageToBytes(img));
            iis = ImageIO.createImageInputStream(is);
            reader.setInput(iis, true);
            
            ImageReadParam param = reader.getDefaultReadParam();
            Rectangle rect = new Rectangle(x, y, width, height);
            param.setSourceRegion(rect);
            BufferedImage bi = reader.read(0, param);
            
            return bufferedImageToBytes(bi);
        }
        finally
        {
            CloseUtils.close(iis);
            CloseUtils.close(is);
            CloseUtils.close(out);
        }
    }
    
    
    /**
     * 图片缩放
     * @param sorcePath 原始图片地址
     * @param destPath 生成图片地址
     * @param width 缩放宽度
     * @param height 缩放高度
     * @param isSameCompress 是否需要等比缩放
     * @return 生成文件
     * @throws IOException
     * @throws ImageFormatException 
     * @see [类、类#方法、类#成员]
     */
    public static File resize(String sorcePath, String destPath, int width, int height, boolean isSameCompress)
        throws IOException, ImageFormatException
    {
        File file = new File(sorcePath);// 读入文件
        Image img = ImageIO.read(file); // 构造Image对象
        int sorceWidth = img.getWidth(null); // 得到源图宽
        int sorceHeight = img.getHeight(null); // 得到源图长
        
        int h = height;
        int w = width;
        if (isSameCompress)
        {
            // 等比缩放
            if (sorceWidth / sorceHeight > width / height)
            {
                h = (int)(sorceHeight * width / sorceWidth);
            }
            else
            {
                w = (int)(sorceWidth * height / sorceHeight);
            }
        }
        
        return drawImage(w, h, img, destPath);
    }
    
    
    /**
     * 图片缩放
     * @param sorcePath 原始图片地址
     * @param destPath 生成图片地址
     * @param width 缩放宽度
     * @param height 缩放高度
     * @param isSameCompress 是否需要等比缩放
     * @return 生成文件
     * @throws IOException
     * @throws ImageFormatException 
     * @see [类、类#方法、类#成员]
     */
    public static File resize(URL sorcePath, String destPath, int width, int height, boolean isSameCompress)
        throws IOException, ImageFormatException
    {
        Image img = ImageIO.read(sorcePath); // 构造Image对象
        int sorceWidth = img.getWidth(null); // 得到源图宽
        int sorceHeight = img.getHeight(null); // 得到源图长
        
        int h = height;
        int w = width;
        if (isSameCompress)
        {
            // 等比缩放
            if (sorceWidth / sorceHeight > width / height)
            {
                h = (int)(sorceHeight * width / sorceWidth);
            }
            else
            {
                w = (int)(sorceWidth * height / sorceHeight);
            }
        }
        
        return drawImage(w, h, img, destPath);
    }
    
    /**
     * 图片缩放
     * @param sorcePath 网络原始图片地址
     * @param width 缩放宽度
     * @param height 缩放高度
     * @param isSameCompress 是否需要等比缩放
     * @return 生成文件
     * @throws IOException
     * @throws ImageFormatException 
     * @see [类、类#方法、类#成员]
     */
    public static byte[] resizeToByte(URL sorcePath, int width, int height, boolean isSameCompress)
        throws IOException, ImageFormatException
    {
        Image img = ImageIO.read(sorcePath); // 构造Image对象
        int sorceWidth = img.getWidth(null); // 得到源图宽
        int sorceHeight = img.getHeight(null); // 得到源图长
        
        int h = height;
        int w = width;
        if (isSameCompress)
        {
            // 等比缩放
            if (sorceWidth / sorceHeight > width / height)
            {
                h = (int)(sorceHeight * width / sorceWidth);
            }
            else
            {
                w = (int)(sorceWidth * height / sorceHeight);
            }
        }
        
        return drawImageToByte(w, h, img);
    }
    
    /**
     * 在图片中增加字符
     * @param sorcePath 图片原始路径
     * @param targetPath 图片目标路径
     * @param picWord 图片中文字描述
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static void picWriteWord(String sorcePath, String targetPath, PicWrod picWord) throws IOException
    {
        // 读取本地文件
        final BufferedImage img = ImageIO.read(new File(sorcePath));
        
        drawWord(img, picWord);
        
        ImageIO.write(img, "jpg", new File(targetPath));
    }
    
    /**
     * 在图片多处地方增加字符
     * @param sorcePath 图片原始路径
     * @param targetPath 图片目标路径
     * @param picWords 图片中文字描述集合
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static void picWriteWords(String sorcePath, String targetPath, List<PicWrod> picWords) throws IOException
    {
        picWriteWords(sorcePath, targetPath, picWords, "jpg");
    }
    

    /**
     * 在图片多处地方增加字符
     * @author  zlm
     * @param sorcePath 图片原始路径
     * @param targetPath 图片目标路径
     * @param picWords 图片中文字描述集合
     * @param formatName 包含格式非正式名称的 String：如JPG、JPEG、GIF等
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static void picWriteWords(String sourcePath, String targetPath, List<PicWrod> picWords, String formatName) throws IOException
    {
        // 读取本地文件
        BufferedImage image = ImageIO.read(new File(sourcePath));
        // 写入文字
        picWriteWords(image, picWords);
        // 写到文件
        ImageIO.write(image, formatName, new File(targetPath));
    }
    
    /**
     * 在图片多处地方增加字符
     * <功能详细描述>
     * @author  zlm
     * @param builder
     * @param picWords
     * @throws IOExceptionvoid
     * @see [类、类#方法、类#成员]
     */
    public static void picWriteWords(BufferedImage image, List<PicWrod> picWords) throws IOException
    {
        // 读取本地文件
        for (PicWrod picWrod : picWords)
        {
            drawWord(image, picWrod);
        }
    }

    /**
     * 在图片多处地方增加字符
     * 
     * @param sorcePath 图片原始路径
     * @param targetPath 图片目标路径
     * @param picWords 图片中文字描述集合
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static byte[] picWriteWords(byte[] pic, List<PicWrod> picWords)
        throws IOException
    {
        ByteArrayInputStream in = new ByteArrayInputStream(pic);
        // 读取本地文件
        BufferedImage img = ImageIO.read(in);
        
        for (PicWrod picWrod : picWords)
        {
            drawWord(img, picWrod);
        }
        
        return bufferedImageToBytes(img);
    }

    /**
     * 添加水印图片
     * <功能详细描述>
     * @author  zlm
     * @param waterMarkImg 水印图片
     * @param srcImgPath 源图像地址
     * @param destImgPath 目标图像地址
     * @param formatName 包含格式非正式名称的 String：如JPG、JPEG、GIF等
     * @param x 起始坐标x
     * @param y 起始坐标y
     * @param alpha 透明度：alpha 必须是范围 [0.0, 1.0] 之内（包含边界值）的一个浮点数字
     * @see [类、类#方法、类#成员]
     */
    public static void picMergeWater(String waterMarkImg, String srcImgPath,
            String destImgPath, String formatName, int x, int y, float alpha) throws IOException
    {
        //原始图片
        BufferedImage image = ImageIO.read(new File(srcImgPath));
        //水印图片
        picMergeWater(image, waterMarkImg, x, y, alpha);

        //生成水印合成图
        ImageIO.write(image, formatName, new File(destImgPath));
    }

    /**
     * 添加图片水印
     * <功能详细描述>
     * @author  zlm
     * @param image
     * @param graphics
     * @param waterMarkImg
     * @param x
     * @param y
     * @param alpha
     * @throws IOExceptionvoid
     * @see [类、类#方法、类#成员]
     */
    public static void picMergeWater(BufferedImage image, String waterMarkImg, 
            int x, int y, float alpha) throws IOException
    {
        //水印图片
        BufferedImage srcWater = null;
        if (waterMarkImg.startsWith("http://"))
        {
            srcWater = ImageIO.read(new URL(waterMarkImg));
        }
        else
        {
            srcWater = ImageIO.read(new File(waterMarkImg));
        }
        picMergeWater(image, srcWater, x, y, alpha);
    }

    /**
     * 添加图片水印
     * <功能详细描述>
     * @author  zlm
     * @param image
     * @param srcWater
     * @param x
     * @param y
     * @param alpha
     * @throws IOExceptionvoid
     * @see [类、类#方法、类#成员]
     */
    public static void picMergeWater(BufferedImage image, BufferedImage srcWater, 
            int x, int y, float alpha) throws IOException
    {
        //获取画笔
        Graphics2D graphics = image.createGraphics();
        try
        {
            //水印图片
            int widethWater = srcWater.getWidth();
            int heightWater = srcWater.getHeight();
            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
            graphics.drawImage(srcWater, x, y, widethWater, heightWater, null);
        }
        finally
        {
            //释放
            graphics.dispose();
        }
    }
    
    /**
     * 读取图片
     * <功能详细描述>
     * @author  zlm
     * @param filePath
     * @return
     * @throws IOExceptionBufferedImage
     * @see [类、类#方法、类#成员]
     */
    public static BufferedImage readImage(String filePath) throws IOException
    {
        BufferedImage image = null;
        if (filePath.startsWith("http://"))
        {
            image = ImageIO.read(new URL(filePath));
        }
        else
        {
            image = ImageIO.read(new File(filePath));
        }
        return image;
    }

    /**
     * 创建透明背景
     * <功能详细描述>
     * @author  zlm
     * @param width
     * @param height
     * @param imageType
     * @returnBufferedImage
     * @see [类、类#方法、类#成员]
     */
    public static BufferedImage createTranslucent(int width, int height, int imageType)
    {
        BufferedImage buffer = new BufferedImage(width, height, imageType);
        Graphics2D graphics = buffer.createGraphics();
        
        buffer = graphics.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        graphics.dispose();
        
        return buffer;
    }

    /**
     * 写入图片文件
     * <功能详细描述>
     * @author  zlm
     * @param image
     * @param targetPath
     * @param formatName
     * @throws IOExceptionvoid
     * @see [类、类#方法、类#成员]
     */
    public static void toFile(BufferedImage image, String targetPath, String formatName) throws IOException
    {
        ImageIO.write(image, formatName, new File(targetPath));
    }

    private static void drawWord(BufferedImage img, PicWrod picWord) throws IOException
    {
        // 得到画笔
        Graphics2D graphics2D = img.createGraphics();
        try
        {
            //字体颜色
            graphics2D.setColor(picWord.getWordColor());
            // 设置字体
            graphics2D.setFont(picWord.getFont());
            // 画图
            if (StringUtils.isNotEmpty(picWord.getContent()))
            {
                graphics2D.drawString(picWord.getContent(), picWord.getX(), picWord.getY());
            }
        }
        finally
        {
            // 释放
            graphics2D.dispose();
        }
    }
    
    private static File drawImage(int width, int height,Image img,String destPath) throws ImageFormatException, IOException 
    {
        // SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        image.getGraphics().drawImage(img, 0, 0, width, height, null); // 绘制缩小后的图
        File destFile = new File(destPath);
        FileOutputStream out = null;
        try
        {
            out = new FileOutputStream(destFile);
            // 输出到文件流
            // 可以正常实现bmp、png、gif转jpg5
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            encoder.encode(image); // JPEG编码
            out.close();
        }
        finally
        {
            CloseUtils.close(out);
        }
        return destFile;
    }
    
    
    private static byte[] drawImageToByte(int width, int height,Image img) throws ImageFormatException, IOException 
    {
        // SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        image.getGraphics().drawImage(img, 0, 0, width, height, null); // 绘制缩小后的图
        ByteArrayOutputStream out = null;
        try
        {
            out = new ByteArrayOutputStream();
            // 输出到文件流
            // 可以正常实现bmp、png、gif转jpg5
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            encoder.encode(image); // JPEG编码
            out.close();
        }
        finally
        {
            CloseUtils.close(out);
        }
        return out.toByteArray();
    }
}
